#include "core/sockness.h"

struct sockaddr_in create_addr(const ushort &port, const char *addr) {
	struct sockaddr_in tarAddr = {};
	tarAddr.sin_family         = AF_INET;
	tarAddr.sin_addr.s_addr    = inet_addr(addr);
	tarAddr.sin_port           = htons(port);
	return tarAddr;
}

/// @brief 		创建UDP套接字
/// @param port 如果为0，则不绑定端口
/// @return 	Socket套接字
int create_udp_socket(const ushort port) {
	// 创建套接字
	int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (sockfd < 1) {
		log_fatal("socket create failed.");
		return -1;
	}

	// 设置非阻塞
	int flags = fcntl(sockfd, F_GETFL, 0);
	fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

	// 允许地址重用
	int reuse = 1;
	if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) < 0) {
		close(sockfd);
		log_fatal("socket setsockopt-reuse failed.");
		return -1;
	}

	if (port == 0) return sockfd;

	// 绑定套接字
	struct sockaddr_in localAddr = create_addr(port);
	if (::bind(sockfd, (struct sockaddr *) &localAddr, sizeof(localAddr)) < 0) {
		close(sockfd);
		log_fatal("socket bind failed.");
		return -1;
	}
	return sockfd;
}

/// @brief 		动态创建UDP套接字
/// @return 	pair<SocketFd,Port>
fdport create_udp_socket_dynamic() {
	int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (sockfd < 1) {
		log_fatal("socket create failed.");
		return make_pair(0, 0);
	}

	// 设置非阻塞
	int flags = fcntl(sockfd, F_GETFL, 0);
	fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

	// 允许地址重用
	int reuse = 1;
	if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) < 0) {
		close(sockfd);
		log_fatal("socket setsockopt-reuse failed.");
		return make_pair(0, 0);
	}

	sockaddr_in server_addr = create_addr(0);
	if (::bind(sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1) {
		close(sockfd);
		log_fatal("socket bind failed.");
		return make_pair(0, 0);
	}

	socklen_t len = sizeof(server_addr);
	getsockname(sockfd, (struct sockaddr *) &server_addr, &len);
	int port = ntohs(server_addr.sin_port);

	return make_pair(sockfd, port);
}
